import json

import requests

import data
from bs4 import BeautifulSoup
import app
import logging
from logging import handlers
import pymysql
import traceback
import base64
import hashlib
import json
import re
import traceback
from Crypto.Cipher import AES


# 日志初始化
def init_log():
    # 1.创建日志器对象
    logger = logging.getLogger()
    # 设置日志器级别
    logger.setLevel(logging.INFO)

    # 2.创建处理器对象
    sh = logging.StreamHandler()
    log_file = app.BATH_DIR + "/log/P2P.log"
    fh = logging.handlers.TimedRotatingFileHandler(log_file,
                                                   when="midnight",
                                                   interval=1,
                                                   backupCount=7,
                                                   encoding="UTF-8")

    # 3.创建格式化器对
    fmt = "%(asctime)s %(levelname)s [%(name)s] [%(filename)s(%(funcName)s:%(lineno)d)] - %(message)s"
    formatter = logging.Formatter(fmt)

    # 4.将格式化器对象添加到处理器对象
    sh.setFormatter(formatter)
    fh.setFormatter(formatter)

    # 5.将处理器对象添加到日志器对象
    logger.addHandler(sh)
    logger.addHandler(fh)


# 封装调用数据库的方法
def use_sql(phone):
    # 创建数据库对象
    conn = pymysql.connect(host="121.43.169.97",
                           database="czbk_member",
                           user="root",
                           password="Itcast_p2p_20191228",
                           port=3306,
                           autocommit=True)

    # 创建游标对象
    cur = conn.cursor()

    # sql语句并执行
    sql = "delete mm,mmi,mmrl from mb_member mm inner join mb_member_info mmi " \
          "on mm.name = mmi.member_name inner join mb_member_register_log mmrl " \
          "on mm.name = mmrl.member_name " \
          "where mm.name = '{}'".format(phone)
    cur.execute(sql)

    # 查询执行结果
    print("sql语句执行后影响的总行数：", cur.rowcount)

    # 关闭数据库游标对象
    cur.close()

    # 关闭数据库对象
    conn.close()


# 公共断言
def common_assert(self, response, status_code, status, description):
    self.assertEqual(status_code, response.status_code)
    self.assertEqual(status, response.json().get("status"))
    if description is not None:
        self.assertIn(description, response.json().get("description"))


class DBUtil:

    @classmethod
    def get_conn(cls):
        return pymysql.connect(host="121.43.169.97",
                               database="czbk_member",
                               user="root",
                               password="Itcast_p2p_20191228",
                               port=3306,
                               autocommit=True)

    @classmethod
    def close_conn(cls, conn):
        if conn:
            conn.close()
            conn = None

    @classmethod
    def get_one(cls, *sql):
        conn = None
        cur = None
        result = None
        try:
            # 创建数据库连接
            conn = cls.get_conn()
            # 创建游标对象
            cur = conn.cursor()
            print("sql====", sql)
            # 执行sql语句
            for s in sql:
                cur.execute(s)
            # 输出执行结果
            result = cur.fetchone()
            print("sql语句执行的结果为：{}".format(cur.rowcount))

        except Exception as e:
            print("查询一条语句出现异常：{}".format(e))
            traceback.print_exc()

        finally:
            if cur:
                cur.close()
            cls.close_conn(conn)
        return result

    @classmethod
    def update_one(cls, *sql):
        conn = None
        cur = None

        try:
            # 创建数据库连接
            conn = cls.get_conn()
            # 创建游标对象
            cur = conn.cursor()
            print("sql====", sql)
            # 执行sql语句
            for s in sql:
                cur.execute(s)
                # 输出执行结果
                print("sql语句执行的结果为：{}".format(cur.rowcount))

        except Exception as e:
            print("新增，修改sql语句出现异常：{}".format(e))
            traceback.print_exc()


        finally:
            if cur:
                cur.close()
            cls.close_conn(conn)


# 创建bs对象
def parse_html(html):
    soup = BeautifulSoup(html, "html.parser")
    action = soup.form.get("action")
    form_data = {}
    for data in soup.find_all("input"):
        name = data["name"]
        value = data["value"]
        form_data[name] = value
    return action, form_data


# 读取外部文件（初级）
def read_file(file):
    data_path = app.BATH_DIR + "/data/" + file + ".json"
    test_data = []
    with open(data_path, encoding="UTF-8") as f:
        json_data = json.load(f)
        print("读取的json数据：", json_data)
        for data in json_data:
            test_data.append(tuple(data.values()))
        print("test_data=", test_data)
    return test_data


# 读取外部文件（高级）
def read_file_freedom(file, keys):
    data_path = app.BATH_DIR + "/data/" + file + ".json"

    # 将keys分割为一个列表
    list_keys = keys.split(",")
    # 定义一个空列表用于存储提取的数据
    test_data = []
    with open(data_path, encoding="UTF-8") as f:
        json_data = json.load(f)
        print("读取的json数据：", json_data)
        for data in json_data:
            values_list = []
            for key in list_keys:
                values = data.get(key)
                values_list.append(values)
            test_data.append(values_list)
        print("test_data=", test_data)
    return test_data


# 加解密工具类
class EncryptUtil:
    # 发送请求时，加密密码
    SEND_AES_KEY = ";3jm$>/p-ED^cVz_j~.KV&V)k9jn,UAH"
    # 发送请求时，签名密钥
    SEND_SIGN_KEY = "DY34fdgsWET@#$%wg#@4fgd345sg"
    # 接收数据时，解密密钥
    RECEIVE_AES_KEY = "54Ms5bkE6UEdyrRviJ0![OR]g+i79x]k"

    @staticmethod
    def get_diyou(data):
        # 把字典转换为JSON字符串
        if isinstance(data, dict):
            data = json.dumps(data)
        aes_encrypt_data = EncryptUtil.aes_encrypt(EncryptUtil.SEND_AES_KEY, data)
        return EncryptUtil.replace_blank(aes_encrypt_data)

    @staticmethod
    def get_xmdy(data):
        return EncryptUtil.md5value(
            EncryptUtil.SEND_SIGN_KEY + EncryptUtil.replace_blank(data) + EncryptUtil.SEND_SIGN_KEY)

    @staticmethod
    def decrypt_data(data):
        return EncryptUtil.aes_decrypt(EncryptUtil.RECEIVE_AES_KEY, data)

    @staticmethod
    def aes_encrypt(key, data):
        """
        AES加密
        :param key: 密钥
        :param data: 待加密数据
        :return: 加密后数据
        """
        data = base64.encodebytes(data.encode()).decode()
        # 替换特殊字符
        data = EncryptUtil.replace_blank(data)
        # print("data=", data)

        # 初始化加密器
        aes = AES.new(key.encode(), AES.MODE_ECB)

        # 解密
        padding_value = EncryptUtil.padding_pkcs5(data)
        encrypt_aes = aes.encrypt(padding_value)

        # 用base64转成字符串形式
        encrypted_text = base64.encodebytes(encrypt_aes).decode()
        return encrypted_text

    @staticmethod
    def aes_decrypt(key, data):
        """
        AES解密
        :param key: 密钥
        :param data: 待解密数据
        :return: 解密后数据
        """
        # 初始化加密器
        aes = AES.new(key.encode(), AES.MODE_ECB)
        # 优先逆向解密base64成bytes
        base64_decrypted = base64.decodebytes(data.encode())

        # 执行解密
        decrypted_bytes = base64.decodebytes(aes.decrypt(base64_decrypted))
        # 转换为字符串
        decrypted_text = str(decrypted_bytes, encoding="utf-8")

        # 把Unicode转成中文
        result = decrypted_text.encode().decode("unicode_escape")
        return result

    @staticmethod
    def md5value(data):
        # print("md5value data=", data)
        md5 = hashlib.md5()
        md5.update(data.encode())
        return md5.hexdigest()

    @staticmethod
    def padding_pkcs5(value):
        BS = AES.block_size
        return str.encode(value + (BS - len(value) % BS) * chr(BS - len(value) % BS))

    # 替换空字符
    @staticmethod
    def replace_blank(str_data):
        str_data = re.compile("\t|\r|\n").sub("", str_data)
        # print("replace_blank str_data=", str_data)
        return str_data


def send_app_requests(url, login_form):
    # 对请求数据进行加密
    diyou = EncryptUtil.get_diyou(login_form)
    xmdy = EncryptUtil.get_xmdy(diyou)
    print("diyou=====", diyou)
    print("xmdy=====", xmdy)

    # 发送请求
    res = requests.post(url=url, data={"diyou": diyou, "xmdy": xmdy})
    res_json = res.json()
    print("登录的响应结果为：{}".format(res_json))
    res_diyou = res_json.get("diyou")
    print("res_diyou====", res_diyou)

    # 对响应数据进行解密
    decrypted_data = EncryptUtil.decrypt_data(res_diyou)
    print("res_diyou解密后====", decrypted_data)
    print(type(decrypted_data))

    # 断言
    decrypted_json_data = json.loads(decrypted_data)
    return decrypted_json_data


if __name__ == '__main__':
    # sql1 = "delete from mb_member where name = '13203003599'"
    # sql2 = "delete from mb_member_info where member_name = '13203003591'"
    # sql3 = "delete from mb_member_register_log where member_name = '13203003591'"
    # r = DBUtil.update_one(sql1, sql2, sql3)
    # print(r)
    read_file_freedom("img_data", "desc,num,status")

    # 加密
    send_data = {}
    content = json.dumps(send_data)
    diyou = EncryptUtil.get_diyou(content)
    print("diyou=", diyou)
    xmdy = EncryptUtil.get_xmdy(diyou)
    print("xmdy=", xmdy)
